package com.apes.hr.area.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.MapUtil;
import com.apes.hr.area.model.DeptArea;
import com.apes.hr.area.model.DeptAreaItem;
import com.apes.hr.area.model.DeptAreaLogger;
import com.apes.hr.area.repository.DeptAreaItemRepository;
import com.apes.hr.area.repository.DeptAreaLoggerRepository;
import com.apes.hr.area.repository.DeptAreaRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apestech.framework.json.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Title: DeptAreaService
 * @Description: 门店区域配置
 * @author: ZhengZeXian
 * @create: 2021/8/19 10:45
 */
@Service("deptAreaService")
public class DeptAreaService extends DomainService {

    @Autowired
    private DeptAreaRepository deptAreaRepository;
    @Autowired
    private DeptAreaItemRepository deptAreaItemRepository;
    @Autowired
    private DeptAreaLoggerRepository deptAreaLoggerRepository;

    public DeptArea save(SimpleRequest request){
        DeptArea deptArea = request.getO(DeptArea.class);
        checkName(deptArea);
        checkItem(deptArea);
        codeGeneration(deptArea);
        return saveAndLoggerByCreate(deptArea);
    }

    public DeptArea update(SimpleRequest request) {
        DeptArea deptArea = request.getO(DeptArea.class);
        checkName(deptArea);
        checkData(request);
        checkItem(deptArea);
        return saveAndLoggerByUpdate(deptArea);
    }

    public String delete(SimpleRequest request) {
        checkData(request);
        deptAreaRepository.delete((String) request.get("id"));
        return "删除成功！";
    }

    /**
     * 根据上级区域编码生成
     * @param deptArea
     */
    public void codeGeneration(DeptArea deptArea){
        if(deptArea.getParents() != null){
            String maxId = deptAreaRepository.findMaxId(deptArea.getParents().getId());
            if (maxId != null){
                String sub = maxId.substring(maxId.length() - 3);
                // 0 代表前面补充0
                // 4 代表长度为4
                // d 代表参数为正数型
                String newId = deptArea.getParents().getId() + String.format("%03d", Integer.valueOf(sub) + 1);
                deptArea.setId(newId);
            }else {
                deptArea.setId(deptArea.getParents().getId() + "001");
            }
        }
    }

    /**
     * 数据检查
     */
    private void checkData(SimpleRequest request) {
        String id = request.get("id");
        DeptArea deptArea = deptAreaRepository.findOne(id);
        Optional.ofNullable(deptArea).orElseThrow(() -> new RuntimeException(String.format("区域配置不存在请重新检查！！！", id)));
        if (deptArea.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
    }

    /**
     * 检查 上级分类下是否存在相同名称的
     * @param deptArea
     */
    private void checkName(DeptArea deptArea){
        if (deptArea.getParents() != null){
            DeptArea byDept = deptAreaRepository.findByParentsAndName(deptArea.getParents(), deptArea.getName());
            if(byDept != null) {
                if(deptArea.getId() == null){
                    throw new RuntimeException(deptArea.getParents().getName() + "  下已存在名称 " + deptArea.getName());
                } else {
                    if (!deptArea.getId().equals(byDept.getId())){
                        throw new RuntimeException(deptArea.getParents().getName() + "  下已存在名称 " + deptArea.getName());
                    }
                }
            }
            if (deptArea.getParents().getName().equals(deptArea.getName())){
                throw new RuntimeException(deptArea.getName() + " 与上级区域名称重复！！！");
            }
        }
        DeptArea byName = deptAreaRepository.findByName(deptArea.getName());
        if(byName != null){
            if(deptArea.getId() == null){

                throw new RuntimeException(deptArea.getName() + " 区域名称已存在！！！");

            }else {
                if (!deptArea.getId().equals(byName.getId())){
                    throw new RuntimeException(deptArea.getName() + " 区域名称已存在！！！");
                }
            }
        }
    }

    /**
     * 检查区域门店配置明细
     * @param deptArea
     */
    private void checkItem(DeptArea deptArea) {
        List<DeptAreaItem> deptAreaItems = deptArea.getDeptAreaItems();
        if (deptArea.isLastStage() && deptArea.getDeptAreaItems().size() == 0 && deptArea.getDeptAreaItems().isEmpty()){
            throw new RuntimeException("所选区域是末级区域必须填写门店配置！！！");
        }
        if (!deptArea.isLastStage() && deptArea.getDeptAreaItems().size() != 0 && !deptArea.getDeptAreaItems().isEmpty()){
            throw new RuntimeException("所选区域不是末级区域不能填写门店配置！！！");
        }
        if (!deptAreaItems.isEmpty()){
            if (itemIsRepeat(deptAreaItems)) throw new RuntimeException("门店区域配置中门店有重复请检查！！！");
            deptAreaItems.stream().forEach(deptAreaItem -> {
                DeptAreaItem byDept = deptAreaItemRepository.findByDept(deptAreaItem.getDept());
                if(byDept != null) {
                    if(deptArea.getId() == null){
                        throw new RuntimeException(deptAreaItem.getDept().getName() + "  已经关联区域： " + byDept.getDeptArea().getName());
                    }else {
                        if (!deptArea.getId().equals(byDept.getDeptArea().getId())){
                            throw new RuntimeException(deptAreaItem.getDept().getName() + "  已经关联区域： " + byDept.getDeptArea().getName());
                        }
                    }
                }
            });
        }
    }

    /**
     * 检查明细是否有重复
     */
    private Boolean itemIsRepeat(List<DeptAreaItem> deptAreaItems) {
        Set<DeptAreaItem> set = new TreeSet<DeptAreaItem>(new Comparator<DeptAreaItem>() {
            public int compare(DeptAreaItem a, DeptAreaItem b) {
                // 字符串则按照asicc码升序排列
                return a.getDept().getId().compareTo(b.getDept().getId());
            }
        });
        set.addAll(deptAreaItems);
        if (set.size() < deptAreaItems.size()) {
            return true;
        }
        return false;
    }

    private List<DeptArea> synDeptArea(SimpleRequest request){
        Date date = new Date();
        JSONObject jo = request.getJO();
        String time = jo.getString("time");
        date.setTime(Long.valueOf(time));
        return deptAreaRepository.findAll(JpaDsl.toCriteria("lastUpdatedStamp", "GTE", date), new Sort(Sort.Direction.ASC, "lastUpdatedStamp"));
    }

    /**
     * 新增或修改数据，并记录门店区域日志
     * @param deptArea
     * @return
     */
    private DeptArea saveAndLoggerByUpdate(DeptArea deptArea){
        // 编辑需要对比旧数据与新数据
        // 判断新增的数据与删除的数据与修改的数据
            // 新增数据与删除数据分别记录关联时间与终止时间
            // 修改数据需要记录旧门店的终止时间与新门店的关联时间
        List<Map> oldItems = deptAreaRepository.findOne(deptArea.getId()).getDeptAreaItems().stream().map(item -> {
            return MapUtil.mapper("id",item.getId(),"deptId",item.getDept().getId(),"deptAreaId",item.getDeptArea().getId(),"deptAreaName",item.getDeptArea().getName());
        }).collect(Collectors.toList());
        deptArea = deptAreaRepository.saveAndFlush(deptArea);
        addUpdateLogger(deptArea,oldItems);
        return deptArea;
    }

    /**
     * 记录门店区域日志
     * @param deptArea
     */
    private void addUpdateLogger(DeptArea deptArea,List<Map> oldItems){
        List<DeptAreaLogger> deptAreaLoggers = new ArrayList<>();
        deptArea.getDeptAreaItems().forEach(deptAreaItem -> {
            // 新增数据：与旧数据明细id不匹配
            boolean isCreate = true;
            for (Map oldItem : oldItems) {
                String oldId = (String) oldItem.get("id");
                String oldDeptId = (String) oldItem.get("deptId");
                String oldDeptAreaId = (String) oldItem.get("deptAreaId");
                if (deptAreaItem.getId().equals(oldId)){
                    isCreate = false;
                    break;
                }
            }
            if (isCreate) deptAreaLoggers.add(wrapDeptAreaLogger(deptAreaItem,"create",null));
        });
        // 修改数据：与旧数据明细id匹配，且门店、区域不一致
        deptArea.getDeptAreaItems().forEach(deptAreaItem -> {
            for (Map oldItem : oldItems) {
                String oldId = (String) oldItem.get("id");
                String oldDeptId = (String) oldItem.get("deptId");
                // 修改数据：与旧数据明细id匹配，且门店、区域不一致
                if (deptAreaItem.getId().equals(oldId) && !deptAreaItem.getDept().getId().equals(oldDeptId)){
                    deptAreaLoggers.add(wrapDeptAreaLogger(oldItem,"end",deptAreaItem.getUpdateDate()));  // 旧门店终止记录
                    deptAreaLoggers.add(wrapDeptAreaLogger(deptAreaItem,"create",deptAreaItem.getUpdateDate()));  // 新门店创建记录
                }
            }
        });
        // 旧数据：与旧数据明细id匹配，且门店、区域都一致  (记录end状态)
        oldItems.forEach(oldItem -> {
            boolean isEnd = true;
            String oldId = (String) oldItem.get("id");
            String oldDeptId = (String) oldItem.get("deptId");
            String oldDeptAreaId = (String) oldItem.get("deptAreaId");
            for (DeptAreaItem deptAreaItem : deptArea.getDeptAreaItems()) {
                if (deptAreaItem.getId().equals(oldId)){
                    isEnd = false;
                    break;
                }
            }
            if (isEnd) {

                oldItem.put("changeDate",new Date());
                deptAreaLoggers.add(wrapDeptAreaLogger(oldItem,"end",null));  // 旧门店终止记录
            }
        });
        if (!deptAreaLoggers.isEmpty()) deptAreaLoggerRepository.saveAll(deptAreaLoggers);
    }

    /**
     * 创建时调用记录门店区域日志
     * @param deptArea
     * @return
     */
    private DeptArea saveAndLoggerByCreate(DeptArea deptArea){
        deptArea = deptAreaRepository.saveAndFlush(deptArea);
        if (!deptArea.getDeptAreaItems().isEmpty()) addCreateLogger(deptArea);
        return deptArea;
    }

    private void addCreateLogger(DeptArea deptArea){
        // 创建只需要记录门店、区域、关联时间
        List<DeptAreaLogger> deptAreaLoggers = new ArrayList<>();
        deptArea.getDeptAreaItems().stream().forEach(item -> {
                deptAreaLoggers.add(wrapDeptAreaLogger(item,"create",null));
        });
        deptAreaLoggerRepository.saveAll(deptAreaLoggers);
    }


    private DeptAreaLogger wrapDeptAreaLogger(Object o,String state,Date changeDate){
        DeptAreaLogger deptAreaLogger = new DeptAreaLogger();
        if (state.equals("end")){
            Map item = (Map) o;
            deptAreaLogger.setDept(SpringManager.getBean(DeptRepository.class).findOne((String) item.get("deptId")));
            deptAreaLogger.setDeptAreaId((String) item.get("deptAreaId"));
            deptAreaLogger.setDeptAreaName((String) item.get("deptAreaName"));
            if (Objects.isNull(changeDate)) deptAreaLogger.setChangeDate((Date) item.get("changeDate"));
            deptAreaLogger.setState(state);
        }else {
            DeptAreaItem item = (DeptAreaItem) o;
            deptAreaLogger.setDept(item.getDept());
            deptAreaLogger.setDeptAreaId(item.getDeptArea().getId());
            deptAreaLogger.setDeptAreaName(item.getDeptArea().getName());
            if (Objects.isNull(changeDate)) deptAreaLogger.setChangeDate(item.getCreateDate());
            deptAreaLogger.setState(state);
        }
        if (!Objects.isNull(changeDate)) deptAreaLogger.setChangeDate(changeDate);
        return deptAreaLogger;
    }

    /**
     * 门店区域日志记录历史数据（上线前使用，用于维护历史数据）
     *
     * @param request
     */
    public Map deptAreaLoggerByHistoryData(SimpleRequest request) {
        List<DeptAreaLogger> oldDate = deptAreaLoggerRepository.findAll();
        List<DeptAreaItem> deptAreaItems = deptAreaItemRepository.findAll();

        if (!oldDate.isEmpty()) throw new RuntimeException("门店区域日志已存在数据！");
        if (deptAreaItems.isEmpty()) throw new RuntimeException("门店区域明细无数据！");

        List<DeptAreaLogger> deptAreaLoggers = new ArrayList<>();
        deptAreaItems.stream().forEach(item -> {
            deptAreaLoggers.add(wrapDeptAreaLogger(item,"create",null));
        });
        deptAreaLoggerRepository.saveAll(deptAreaLoggers);
        return MapUtil.mapper("success", "true", "msg", "已维护历史数据共" + deptAreaLoggers.size() + "条");
    }
}
